package com.uh.rds.testing.validator.types;

import com.uh.rds.testing.validator.DataValidatorBase;
import redis.clients.jedis.StreamEntryID;
import redis.clients.jedis.resps.StreamEntry;

import java.util.*;

public class StreamDataValidator extends DataValidatorBase {

    @Override
    public String getType() {
        return "Stream";
    }

    @Override
    public void process() {
        if (!processJedis.isConnected()) processJedis.connect();

        processBeginLog();
        for (Map.Entry<String, List<String[]>> entry : data.entrySet()) {
            String key = entry.getKey();
            String[][] values = entry.getValue().toArray(new String[0][0]);

            for (int i = 0; i < values.length; i++) {
                String[] v = values[i];
                Map<String, String> map = new HashMap() {{
                    put(v[0], v[1]);
                }};
                processJedis.xadd(key, StreamEntryID.NEW_ENTRY, map);
            }

            processingLog(true);
        }

        processEndLog();
    }

    @Override
    public long expire(int expireSeconds) {
        return super.expire(processJedis, data.keySet(), expireSeconds);
    }

    @Override
    public boolean validateExpired() {
        return super.validateExpired(validateJedis, data.keySet());
    }


    @Override
    public boolean validate() {
        if (!validateJedis.isConnected()) validateJedis.connect();

        validateBeginLog();

        Collection<String> keys = arguments.isValidateReversed() ? reversedKeys : data.keySet();
        for(String key : keys) {
            boolean keyMatched = true;
            List<String[]> valuesList = data.get(key);
            long expectedSize = valuesList.size();
            long actualSize = validateJedis.xlen(key);
            if (actualSize != expectedSize) {
                keyMatched = false;
                logger.error("{} key[{}] validate failed! Expected size:{} validate size:{}", getName(),  key, expectedSize, actualSize);
            }

            List<StreamEntry> streamEntries = validateJedis.xrange(key, "-", "+", Math.toIntExact(actualSize));
            String[][] localData = valuesList.toArray(new String[0][0]);

            for (int i = 0; i < streamEntries.size(); i++) {
                Map<String, String> fields = streamEntries.get(i).getFields();
                String[] localDatum = localData[i];
                if (fields.containsKey(localDatum[0])) {
                    if (!fields.get(localDatum[0]).equals(localDatum[1])) {
                        keyMatched = false;
                        logger.error("{} key[{}] validate failed! Expected value:{} validate value:{}", getName(), key, localDatum[1], fields.get(localDatum[0]));
                    }
                }
            }

            validatingLog(keyMatched);
        }

        return validateEndLog();
    }

    @Override
    public long clear() {
        return clear(processJedis, validateJedis, data.keySet());
    }
}
